



Console = {
    Out:{
		Write:function(ex, url, lastModified, referrer, args){ 
			//$dm(ex, url, lastModified, referrer, args);
			console.log(ex||"", url||"", lastModified||"", referrer||"", args||"");
		},
		WriteResult:function(cssClass, ex, url, lastModified, referrer, args){ 
			//debugHelper.$Write(cssClass, ex, url, lastModified, referrer, args);
			console.log(ex||"", url||"", lastModified||"", referrer||"", args||"");
		}
	}
}





//Create Is class comparer
Is = {
	EqualTo:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg == this.rightArgument;
		}
	},
	
	NotEqualTo:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg != this.rightArgument;
		}
	},

	GreaterThan:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg > this.rightArgument;
		}
	},
	
	GreaterThanOrEqualTo:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg >= this.rightArgument;
		}
	},
	
	LessThan:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg < this.rightArgument;
		}
	},
	
	LessThanOrEqualTo:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg <= this.rightArgument;
		}
	},
	
	InstanceOf:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg instanceof this.rightArgument;
		}
	},
	
	TypeOf:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return typeof(leftArg) == new String(this.rightArgument).toLowerCase();
		}
	},
	
	StrictEqualTo:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg === this.rightArgument;
		}
	},
	
	StrictNotEqualTo:function(rightArg){
		this.rightArgument = rightArg;
		this.Check = function(leftArg){
			return leftArg !== this.rightArgument;
		}
	}
	
}





Assert = {
    TotalPassed:0,
    TotalFailed:0,
	That:function(leftArg, iConstraint){
		var o;
		
		try{
			o = iConstraint.Check(leftArg)
		}catch(e){
			console.error(leftArg, iConstraint.rightArgument, e);
		}
	
		if( o ){
		    this.TotalPassed++;
			return true;
		}else{
			//console.log("Assert.That: ",leftArg, " == " ,iConstraint.rightArgument, " [ ", o ," ]")
			//debugger;
	        this.TotalFailed++;
			return false;
	    }
	},
	ClearCounters:function(){				
		this.TotalPassed = 0;
		this.TotalFailed = 0;
	}
}


//Test fixture interface
function ITestFixture(){}

ITestFixture.prototype = {
	constructor:ITestFixture,
	Description:"Test fixture.",
    Category:"none",
    StartTime:false,
	EndTime:false,
	Times:1,
    Tests:false,
	
	//Set of functions that are performed once prior to executing any of the tests in the fixture
	TestFixtureSetUp:function(){},
	
	//Set of functions that are performed once after all tests are completed
	TestFixtureTearDown:function(){},
	
	
	//Add a new test case
	AddTest:function(itest){
		if(!this.Tests){
			this.Tests=[];
		};
		
		if(itest instanceof ITest)
		{
			this.Tests.push(itest);
		}
		else if(itest instanceof Array)
		{
			itest.forEach(function(test){
				test.prototype = new ITest();
				test.prototype.constructor = test;
				
				this.Tests.push(new test());
				
			},this)
		}
		else if(itest instanceof Function)
		{
			itest.prototype = new ITest();
			itest.prototype.constructor = itest;
				
			this.Tests.push(new itest());
		}
		
		return this;
		
	},

	//Clear test cases
	Clear:function(){
		this.Tests = [];
	},
	
	//Test cases to be run
	Run:function(){
	    var testFixtureName = /function (.+)\(/.exec(this.constructor.toString())[1];
		console.log("Starting " + (testFixtureName||"anonymous"), ", Description: "+ this.Description, ", Category: " + this.Category);
	    this.TestFixtureSetUp();
		for(var z=0;z<this.Times;z++){
		    for(var i=0;i<this.Tests.length;i++){
		        this.TestFixtureSetUp();
				this.StartTime = new Date();
				this.Tests[i].SetUp();
		        this.Tests[i].Check(i+1);
				this.Tests[i].TearDown();
				this.EndTime = new Date();
		        this.TestFixtureTearDown();
		    }
		};
	    this.TestFixtureTearDown();
	}
}



function ITest(){
	this.StartTime=false;
	this.Test=false;
	this.EndTime=false;
	this.EllapsedTime=false;
	this.Status=false;
}

ITest.prototype = {
	
	//Common set of functions that are performed just before each test method is called
	SetUp:function(){
		
	},

	//Common set of functions that are performed after each test method is run
	TearDown:function(){
		
	},
	
	Check:function(index){
		
		var tf = Assert.TotalFailed
		var tp = Assert.TotalPassed
		
		this.StartTime = new Date();
		this.constructor();
		this.EndTime = new Date();
		
		this.Status = Assert.TotalFailed == tf
		
		this.EllapsedTime = (this.EndTime - this.StartTime);
		
	    var testName = /function (.+)\(/.exec(this.constructor.toString());
			testName = testName ? testName[1] : (this.constructor.name || "anonymous");
		
		if(this.Status){
			console.info(index + "\t SUCCESS,\t\t " + testName, "\t\tTests: " + (Assert.TotalPassed - tp) + "/" + (Assert.TotalFailed - tf));
		}else{
			console.error(index + "\t FAILED,\t\t " + testName, "\t\tTests: " + (Assert.TotalPassed - tp) + "/" + (Assert.TotalFailed - tf));
			//debugger;
		}
		
		return this;
	}
}









//Unit.js engine class	        
UnitJs = {
    StartTime:false,
    TestFixtures:false,
	
	//Add a test fixture to the collection
	AddTestFixture:function(testFixture){
		if(!this.TestFixtures){
			this.TestFixtures=[];
		};
		this.TestFixtures.push(testFixture);
	},

	//Run all fixtures
	Run:function(){
		
		Assert.ClearCounters();

		this.StartTime = new Date();
    
	    for(var i=0;i<this.TestFixtures.length;i++){
	        this.TestFixtures[i].Run();
	    };
	
		this.EndTime = new Date();
	    
	    if( Assert.TotalPassed > 0 ){
	        Console.Out.WriteResult("UnitJsTotalPassed: ", "Total tests passing: " + Assert.TotalPassed);
		};
	    if( Assert.TotalFailed > 0 ){
	        Console.Out.WriteResult("UnitJsTotalFailed: ", "Total tests failing: " + Assert.TotalFailed);
		};
			
	    Console.Out.WriteResult("UnitJsTotal: ", "Total tests run: " + (Assert.TotalPassed + Assert.TotalFailed));

	    Console.Out.Write("Total running time: " + (this.EndTime - this.StartTime) + "s");

	    if( Assert.TotalFailed == 0 ){
	        Console.Out.WriteResult("UnitJsFinalWordGreen", "Passing!");
	    }else{
	        Console.Out.WriteResult("UnitJsFinalWordRed", "Failing!");
		}
	}
}
